// 版权所有2011 Go作者。版权所有。
// 此源代码的使用受BSD样式的约束
// 可以在许可证文件中找到的许可证。

package x509

import (
	"bytes"
	"errors"
	"fmt"
	"net"
	"net/url"
	"reflect"
	"runtime"
	"strings"
	"time"
	"unicode/utf8"
)

type InvalidReason int

const (
	// 当一个证书由另一个证书签名时，将产生NotAuthorizedToSign结果
	// 未标记为CA证书的。
	NotAuthorizedToSign InvalidReason = iota
	// 证书过期时的过期结果（基于时间）
	// 在验证选项中给出。
	Expired
	// CANOTAutAuthorizedForthisname在中间或根
	// 证书具有名称约束，不允许DNS或
	// 叶证书中的其他名称（包括IP地址）。
	CANotAuthorizedForThisName
	// 当路径长度约束为
	// 违反了。
	TooManyIntermediates
	// 当证书的密钥使用指示
	// 它只能用于不同的目的。
	IncompatibleUsage
	// 如果父证书的使用者名称不匹配，则会导致名称不匹配
	// 与子系统中的颁发者名称不匹配。
	NameMismatch
	// NameConstraintsWithoutSANs是一个遗留错误，不再返回。
	NameConstraintsWithoutSANs
	// 当CA证书包含允许的名称时，将生成UnconstrainedName
	// 名称约束，但叶证书包含
	// 不支持或不受约束的类型。
	UnconstrainedName
	// TooManyConstraints当比较操作数
	// 需要检查的证书超过了由设置的限制
	// VerifyOptions.MaxConstraintComparisions。此限制存在于
	// 预防病态证书可能会消耗过量的
	// CPU验证时间。
	TooManyConstraints
	// CANotAuthorizedForExtKeyUsage在中间或根
	// 证书不允许使用请求的扩展密钥。
	CANotAuthorizedForExtKeyUsage
)

// 当发生奇数错误时，CertificateInvalidError将产生。本网站的用户
// 库可能希望统一处理所有这些错误。
type CertificateInvalidError struct {
	Cert   *Certificate
	Reason InvalidReason
	Detail string
}

func (e CertificateInvalidError) Error() string {
	switch e.Reason {
	case NotAuthorizedToSign:
		return "x509: certificate is not authorized to sign other certificates"
	case Expired:
		return "x509: certificate has expired or is not yet valid: " + e.Detail
	case CANotAuthorizedForThisName:
		return "x509: a root or intermediate certificate is not authorized to sign for this name: " + e.Detail
	case CANotAuthorizedForExtKeyUsage:
		return "x509: a root or intermediate certificate is not authorized for an extended key usage: " + e.Detail
	case TooManyIntermediates:
		return "x509: too many intermediates for path length constraint"
	case IncompatibleUsage:
		return "x509: certificate specifies an incompatible key usage"
	case NameMismatch:
		return "x509: issuer name does not match subject from issuing certificate"
	case NameConstraintsWithoutSANs:
		return "x509: issuer has name constraints but leaf doesn't have a SAN extension"
	case UnconstrainedName:
		return "x509: issuer has name constraints but leaf contains unknown or unconstrained name: " + e.Detail
	}
	return "x509: unknown error"
}

// 当授权名称集与
// 请求的名称。
type HostnameError struct {
	Certificate *Certificate
	Host        string
}

func (h HostnameError) Error() string {
	c := h.Certificate

	if !c.hasSANExtension() && matchHostnames(c.Subject.CommonName, h.Host) {
		return "x509: certificate relies on legacy Common Name field, use SANs instead"
	}

	var valid string
	if ip := net.ParseIP(h.Host); ip != nil {
		// 正在尝试验证IP
		if len(c.IPAddresses) == 0 {
			return "x509: cannot validate certificate for " + h.Host + " because it doesn't contain any IP SANs"
		}
		for _, san := range c.IPAddresses {
			if len(valid) > 0 {
				valid += ", "
			}
			valid += san.String()
		}
	} else {
		valid = strings.Join(c.DNSNames, ", ")
	}

	if len(valid) == 0 {
		return "x509: certificate is not valid for any names, but wanted to match " + h.Host
	}
	return "x509: certificate is valid for " + valid + ", not " + h.Host
}

// 当证书颁发者未知时，会产生UnknownAuthority错误
type UnknownAuthorityError struct {
	Cert *Certificate
	// hintErr包含一个错误，该错误可能有助于确定
	// 找不到权威。
	hintErr error
	// hintCert包含一个可能被拒绝的授权证书
	// 因为hintErr中的错误。
	hintCert *Certificate
}

func (e UnknownAuthorityError) Error() string {
	s := "x509: certificate signed by unknown authority"
	if e.hintErr != nil {
		certName := e.hintCert.Subject.CommonName
		if len(certName) == 0 {
			if len(e.hintCert.Subject.Organization) > 0 {
				certName = e.hintCert.Subject.Organization[0]
			} else {
				certName = "serial:" + e.hintCert.SerialNumber.String()
			}
		}
		s += fmt.Sprintf(" (possibly because of %q while trying to verify candidate authority certificate %q)", e.hintErr, certName)
	}
	return s
}

// SystemRootsError在加载系统根证书失败时产生。
type SystemRootsError struct {
	Err error
}

func (se SystemRootsError) Error() string {
	msg := "x509: failed to load system roots and no roots provided"
	if se.Err != nil {
		return msg + "; " + se.Err.Error()
	}
	return msg
}

func (se SystemRootsError) Unwrap() error { return se.Err }

// 在创建没有ASN.1内容的证书时，返回errNotParsed
// 已证实的平台特定验证需要ASN.1内容。
var errNotParsed = errors.New("x509: missing ASN.1 contents; use ParseCertificate")

// VerifyOptions包含Certificate.Verify的参数。
type VerifyOptions struct {
	// 如果设置了DNSName，则使用
	// Certificate.VerifyHostname或平台验证程序。
	DNSName string

	// 中间人是一个可选的非信任证书池
	// 锚定，但可用于形成从叶证书到
	// 根证书。
	Intermediates *CertPool
	// 根是叶证书所需的受信任根证书集
	// 连锁。如果为nil，则使用系统根或平台验证器。
	Roots *CertPool

	// CurrentTime用于检查中所有证书的有效性
	// 链条如果为零，则使用当前时间。
	CurrentTime time.Time

	// KeyUsages指定可接受的扩展密钥使用值。A.
	// 如果允许任何列出的值，则接受链。空名单
	// 表示ExtKeyUsageServerAuth。要接受任何密钥用法，请包括ExtKeyUsageAny。
	KeyUsages []ExtKeyUsage

	// MaxConstraintComparisions是与的最大比较次数
	// 检查给定证书的名称约束时执行。如果
	// 零，则使用合理的默认值。这一限制可防止病理性疾病
	// 证书在以下情况下不会占用过多的CPU时间：
	// 验证。它不适用于平台验证器。
	MaxConstraintComparisions int
}

const (
	leafCertificate = iota
	intermediateCertificate
	rootCertificate
)

// RFC2821邮箱代表一个“邮箱”（这是大多数人的电子邮件地址）
// 通过将其分为“本地”（即在“@”之前）和“域”
// 部分。
type rfc2821Mailbox struct {
	local, domain string
}

// ParserFC2821邮箱将电子邮件地址解析为本地和域部分，
// 基于RFC 2821中“邮箱”的ABNF。根据RFC 5280，
// 第4.2.1.6节对证书中的RFC822名称是正确的：“
// RFC822名称的格式为RFC 2821第4.1.2节中定义的“邮箱”。
func parseRFC2821Mailbox(in string) (mailbox rfc2821Mailbox, ok bool) {
	if len(in) == 0 {
		return mailbox, false
	}

	localPartBytes := make([]byte, 0, len(in)/2)

	if in[0] == '"' {
		// Quoted string=DQUOTE*qcontent DQUOTE
		// 非空白控件=%d1-8/%d11/%d12/%d14-31/%d127
		// qcontent=qtext/引用对
		// qtext=非空白控件/
		// %d33/%d35-91/%d93-126
		// 引号对=（“\”文本）/obs qp
		// 文本=%d1-9/%d11/%d12/%d14-127/obs文本
		// None
		// （以“obs-”开头的名称是RFC 2822中过时的语法，
		// 第4节。已经16年了，我们不再接受这一点。）
		in = in[1:]
	QuotedString:
		for {
			if len(in) == 0 {
				return mailbox, false
			}
			c := in[0]
			in = in[1:]

			switch {
			case c == '"':
				break QuotedString

			case c == '\\':
				// 引用对
				if len(in) == 0 {
					return mailbox, false
				}
				if in[0] == 11 ||
					in[0] == 12 ||
					(1 <= in[0] && in[0] <= 9) ||
					(14 <= in[0] && in[0] <= 127) {
					localPartBytes = append(localPartBytes, in[0])
					in = in[1:]
				} else {
					return mailbox, false
				}

			case c == 11 ||
				c == 12 ||
				// 基于
				// BNF，但RFC3696给出了一个例子
				// 假设是这样。几个“验证”
				// 勘误表继续争论这一点。
				// 我们选择接受它。
				c == 32 ||
				c == 33 ||
				c == 127 ||
				(1 <= c && c <= 8) ||
				(14 <= c && c <= 31) ||
				(35 <= c && c <= 91) ||
				(93 <= c && c <= 126):
				// qtext
				localPartBytes = append(localPartBytes, c)

			default:
				return mailbox, false
			}
		}
	} else {
		// 原子（“.”原子）*
	NextChar:
		for len(in) > 0 {
			// 来自RFC 2822第3.2.4节的文本
			c := in[0]

			switch {
			case c == '\\':
				// RFC 3696中给出的示例表明
				// 转义字符可以出现在
				// 带引号的字符串。几个“已验证”的勘误表
				// 继续争论这个问题。我们选择
				// 接受它。
				in = in[1:]
				if len(in) == 0 {
					return mailbox, false
				}
				fallthrough

			case ('0' <= c && c <= '9') ||
				('a' <= c && c <= 'z') ||
				('A' <= c && c <= 'Z') ||
				c == '!' || c == '#' || c == '$' || c == '%' ||
				c == '&' || c == '\'' || c == '*' || c == '+' ||
				c == '-' || c == '/' || c == '=' || c == '?' ||
				c == '^' || c == '_' || c == '`' || c == '{' ||
				c == '|' || c == '}' || c == '~' || c == '.':
				localPartBytes = append(localPartBytes, in[0])
				in = in[1:]

			default:
				break NextChar
			}
		}

		if len(localPartBytes) == 0 {
			return mailbox, false
		}

		// 根据RFC 3696第3节：
		// 句点（“.”）也可以出现，但不能用于开始
		// 或结束局部部分，也不得连续两次或两次以上
		// 句号出现了。”
		twoDots := []byte{'.', '.'}
		if localPartBytes[0] == '.' ||
			localPartBytes[len(localPartBytes)-1] == '.' ||
			bytes.Contains(localPartBytes, twoDots) {
			return mailbox, false
		}
	}

	if len(in) == 0 || in[0] != '@' {
		return mailbox, false
	}
	in = in[1:]

	// RFC是域的一种格式，但这是已知的
	// 在实践中被违反，因此我们接受在“@”之后的任何内容都是
	// 域部分。
	if _, ok := domainToReverseLabels(in); !ok {
		return mailbox, false
	}

	mailbox.local = string(localPartBytes)
	mailbox.domain = in
	return mailbox, true
}

// domainToReverseLabels将文本域名（如foo.example.com）转换为
// 按相反顺序排列的标签列表，例如：[“com”、“example”、“foo”]。
func domainToReverseLabels(domain string) (reverseLabels []string, ok bool) {
	for len(domain) > 0 {
		if i := strings.LastIndexByte(domain, '.'); i == -1 {
			reverseLabels = append(reverseLabels, domain)
			domain = ""
		} else {
			reverseLabels = append(reverseLabels, domain[i+1:])
			domain = domain[:i]
		}
	}

	if len(reverseLabels) > 0 && len(reverseLabels[0]) == 0 {
		// 末尾的空标签表示绝对值。
		return nil, false
	}

	for _, label := range reverseLabels {
		if len(label) == 0 {
			// 空标签在其他方面无效。
			return nil, false
		}

		for _, c := range label {
			if c < 33 || c > 126 {
				// 无效字符。
				return nil, false
			}
		}
	}

	return reverseLabels, true
}

func matchEmailConstraint(mailbox rfc2821Mailbox, constraint string) (bool, error) {
	// 如果约束包含@，则它指定确切的邮箱
	// 名称
	if strings.Contains(constraint, "@") {
		constraintMailbox, ok := parseRFC2821Mailbox(constraint)
		if !ok {
			return false, fmt.Errorf("x509: internal error: cannot parse constraint %q", constraint)
		}
		return mailbox.local == constraintMailbox.local && strings.EqualFold(mailbox.domain, constraintMailbox.domain), nil
	}

	// 否则，该约束类似于域部分的DNS约束
	// 邮箱的地址。
	return matchDomainConstraint(mailbox.domain, constraint)
}

func matchURIConstraint(uri *url.URL, constraint string) (bool, error) {
	// 根据RFC 5280第4.2.1.10节：
	// “不包含权限的uniformResourceIdentifier
	// 主机名指定为完全限定域的组件
	// 名称（例如，如果URI不包含权限
	// 组件或包含一个授权组件，其中主机名
	// 指定为IP地址），则应用程序必须拒绝
	// 证书。”

	host := uri.Host
	if len(host) == 0 {
		return false, fmt.Errorf("URI with empty host (%q) cannot be matched against constraints", uri.String())
	}

	if strings.Contains(host, ":") && !strings.HasSuffix(host, "]") {
		var err error
		host, _, err = net.SplitHostPort(uri.Host)
		if err != nil {
			return false, err
		}
	}

	if strings.HasPrefix(host, "[") && strings.HasSuffix(host, "]") ||
		net.ParseIP(host) != nil {
		return false, fmt.Errorf("URI with IP (%q) cannot be matched against constraints", uri.String())
	}

	return matchDomainConstraint(host, constraint)
}

func matchIPConstraint(ip net.IP, constraint *net.IPNet) (bool, error) {
	if len(ip) != len(constraint.IP) {
		return false, nil
	}

	for i := range ip {
		if mask := constraint.Mask[i]; ip[i]&mask != constraint.IP[i]&mask {
			return false, nil
		}
	}

	return true, nil
}

func matchDomainConstraint(domain, constraint string) (bool, error) {
	// 未指定零长度约束的含义，但
	// 代码遵循NSS，并将其视为匹配所有内容。
	if len(constraint) == 0 {
		return true, nil
	}

	domainLabels, ok := domainToReverseLabels(domain)
	if !ok {
		return false, fmt.Errorf("x509: internal error: cannot parse domain %q", domain)
	}

	// RFC 5280说域名中的前导周期意味着
	// 必须至少在前面添加一个标签，但仅适用于URI和电子邮件
	// 约束，而不是DNS约束。代码也支持这一点
	// DNS约束的行为。

	mustHaveSubdomains := false
	if constraint[0] == '.' {
		mustHaveSubdomains = true
		constraint = constraint[1:]
	}

	constraintLabels, ok := domainToReverseLabels(constraint)
	if !ok {
		return false, fmt.Errorf("x509: internal error: cannot parse domain %q", constraint)
	}

	if len(domainLabels) < len(constraintLabels) ||
		(mustHaveSubdomains && len(domainLabels) == len(constraintLabels)) {
		return false, nil
	}

	for i, constraintLabel := range constraintLabels {
		if !strings.EqualFold(constraintLabel, domainLabels[i]) {
			return false, nil
		}
	}

	return true, nil
}

// checkNameConstraints检查c是否允许子证书声明
// 给定名称，类型为nameType。参数parsedName包含已解析的
// 名称的形式，适合传递给match函数。总数
// 在给定的计数中跟踪比较的数量，并且不应超过给定的计数
// 限度
func (c *Certificate) checkNameConstraints(count *int,
	maxConstraintComparisons int,
	nameType string,
	name string,
	parsedName interface{},
	match func(parsedName, constraint interface{}) (match bool, err error),
	permitted, excluded interface{}) error {

	excludedValue := reflect.ValueOf(excluded)

	*count += excludedValue.Len()
	if *count > maxConstraintComparisons {
		return CertificateInvalidError{c, TooManyConstraints, ""}
	}

	for i := 0; i < excludedValue.Len(); i++ {
		constraint := excludedValue.Index(i).Interface()
		match, err := match(parsedName, constraint)
		if err != nil {
			return CertificateInvalidError{c, CANotAuthorizedForThisName, err.Error()}
		}

		if match {
			return CertificateInvalidError{c, CANotAuthorizedForThisName, fmt.Sprintf("%s %q is excluded by constraint %q", nameType, name, constraint)}
		}
	}

	permittedValue := reflect.ValueOf(permitted)

	*count += permittedValue.Len()
	if *count > maxConstraintComparisons {
		return CertificateInvalidError{c, TooManyConstraints, ""}
	}

	ok := true
	for i := 0; i < permittedValue.Len(); i++ {
		constraint := permittedValue.Index(i).Interface()

		var err error
		if ok, err = match(parsedName, constraint); err != nil {
			return CertificateInvalidError{c, CANotAuthorizedForThisName, err.Error()}
		}

		if ok {
			break
		}
	}

	if !ok {
		return CertificateInvalidError{c, CANotAuthorizedForThisName, fmt.Sprintf("%s %q is not permitted by any constraint", nameType, name)}
	}

	return nil
}

// isValid在c上执行有效性检查，因为它是要追加的候选对象
// 到当前链中的链。
func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *VerifyOptions) error {
	if len(c.UnhandledCriticalExtensions) > 0 {
		return UnhandledCriticalExtension{}
	}

	if len(currentChain) > 0 {
		child := currentChain[len(currentChain)-1]
		if !bytes.Equal(child.RawIssuer, c.RawSubject) {
			return CertificateInvalidError{c, NameMismatch, ""}
		}
	}

	now := opts.CurrentTime
	if now.IsZero() {
		now = time.Now()
	}
	if now.Before(c.NotBefore) {
		return CertificateInvalidError{
			Cert:   c,
			Reason: Expired,
			Detail: fmt.Sprintf("current time %s is before %s", now.Format(time.RFC3339), c.NotBefore.Format(time.RFC3339)),
		}
	} else if now.After(c.NotAfter) {
		return CertificateInvalidError{
			Cert:   c,
			Reason: Expired,
			Detail: fmt.Sprintf("current time %s is after %s", now.Format(time.RFC3339), c.NotAfter.Format(time.RFC3339)),
		}
	}

	maxConstraintComparisons := opts.MaxConstraintComparisions
	if maxConstraintComparisons == 0 {
		maxConstraintComparisons = 250000
	}
	comparisonCount := 0

	var leaf *Certificate
	if certType == intermediateCertificate || certType == rootCertificate {
		if len(currentChain) == 0 {
			return errors.New("x509: internal error: empty chain when appending CA cert")
		}
		leaf = currentChain[0]
	}

	if (certType == intermediateCertificate || certType == rootCertificate) &&
		c.hasNameConstraints() && leaf.hasSANExtension() {
		err := forEachSAN(leaf.getSANExtension(), func(tag int, data []byte) error {
			switch tag {
			case nameTypeEmail:
				name := string(data)
				mailbox, ok := parseRFC2821Mailbox(name)
				if !ok {
					return fmt.Errorf("x509: cannot parse rfc822Name %q", mailbox)
				}

				if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "email address", name, mailbox,
					func(parsedName, constraint interface{}) (bool, error) {
						return matchEmailConstraint(parsedName.(rfc2821Mailbox), constraint.(string))
					}, c.PermittedEmailAddresses, c.ExcludedEmailAddresses); err != nil {
					return err
				}

			case nameTypeDNS:
				name := string(data)
				if _, ok := domainToReverseLabels(name); !ok {
					return fmt.Errorf("x509: cannot parse dnsName %q", name)
				}

				if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "DNS name", name, name,
					func(parsedName, constraint interface{}) (bool, error) {
						return matchDomainConstraint(parsedName.(string), constraint.(string))
					}, c.PermittedDNSDomains, c.ExcludedDNSDomains); err != nil {
					return err
				}

			case nameTypeURI:
				name := string(data)
				uri, err := url.Parse(name)
				if err != nil {
					return fmt.Errorf("x509: internal error: URI SAN %q failed to parse", name)
				}

				if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "URI", name, uri,
					func(parsedName, constraint interface{}) (bool, error) {
						return matchURIConstraint(parsedName.(*url.URL), constraint.(string))
					}, c.PermittedURIDomains, c.ExcludedURIDomains); err != nil {
					return err
				}

			case nameTypeIP:
				ip := net.IP(data)
				if l := len(ip); l != net.IPv4len && l != net.IPv6len {
					return fmt.Errorf("x509: internal error: IP SAN %x failed to parse", data)
				}

				if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "IP address", ip.String(), ip,
					func(parsedName, constraint interface{}) (bool, error) {
						return matchIPConstraint(parsedName.(net.IP), constraint.(*net.IPNet))
					}, c.PermittedIPRanges, c.ExcludedIPRanges); err != nil {
					return err
				}

			default:
				// 忽略未知的SAN类型。
			}

			return nil
		})

		if err != nil {
			return err
		}
	}

	// 忽略密钥使用状态标志。来自工程安全部，彼得
	// 古特曼：欧洲政府CA将其签署证书标记为
	// 只对加密有效，但没人注意到。另一个
	// 欧洲CA将其签名密钥标记为对无效
	// 签名。另一个CA标记了它自己的受信任根证书
	// 对于证书签名无效。另一个国家CA
	// 分发了一个证书，用于加密
	// 标记为仅可用于以下目的的国家税务机关：
	// 数字签名，但不用于加密。另一个CA逆转了
	// 由于混淆，密钥用法中位标志的顺序
	// 编码endianness，本质上是在
	// 它颁发的证书。另一个CA创建了一个自失效
	// 通过添加证书策略声明，规定
	// 必须严格按照合同规定使用证书
	// keyUsage和一个keyUsage，其中包含一个标志，指示RSA
	// 加密密钥只能用于Diffie-Hellman密钥协议。

	if certType == intermediateCertificate && (!c.BasicConstraintsValid || !c.IsCA) {
		return CertificateInvalidError{c, NotAuthorizedToSign, ""}
	}

	if c.BasicConstraintsValid && c.MaxPathLen >= 0 {
		numIntermediates := len(currentChain) - 1
		if numIntermediates > c.MaxPathLen {
			return CertificateInvalidError{c, TooManyIntermediates, ""}
		}
	}

	return nil
}

// 验证尝试通过从c到a构建一个或多个链来验证c
// 在opts.root中使用证书，如果
// 需要。如果成功，它将返回一个或多个链，其中第一个
// 链的元素是c，最后一个元素来自opts.root。
// None
// 如果opts.root为nil，则可以使用平台验证器，并且
// 验证详细信息可能与下面描述的不同。中频系统
// 根不可用。返回的错误类型为SystemRootsError。
// None
// 中间产物中的名称约束将应用于所有声称的名称
// 在链中，不只是opts.DNSName。因此，叶声明是无效的
// 如果中间人不允许，即使example.com不允许
// 正在验证的名称。请注意，DirectoryName约束不是
// 支持。
// None
// 名称约束验证遵循RFC 5280中的规则
// 此外，DNS名称约束可能使用前导句点格式
// 为电子邮件和URI定义。当约束具有前导周期时
// 它表示至少必须在前面加上一个附加标签
// 要视为有效的受约束名称。
// None
// 扩展键使用值强制嵌套在一个链中，因此
// 或者，枚举EKUs的根阻止叶断言EKU，而不是在其中
// 列表（虽然没有规定，但通常的做法是限制
// CA可以颁发的证书类型。）
// None
// 警告：此函数不执行任何吊销检查。
func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err error) {
	// 平台特定验证需要ASN.1内容，因此
	// 这使得跨平台的行为一致。
	if len(c.Raw) == 0 {
		return nil, errNotParsed
	}
	for i := 0; i < opts.Intermediates.len(); i++ {
		c, err := opts.Intermediates.cert(i)
		if err != nil {
			return nil, fmt.Errorf("crypto/x509: error fetching intermediate: %w", err)
		}
		if len(c.Raw) == 0 {
			return nil, errNotParsed
		}
	}

	// 使用Windows自己的验证和链构建。
	if opts.Roots == nil && runtime.GOOS == "windows" {
		return c.systemVerify(&opts)
	}

	if opts.Roots == nil {
		opts.Roots = systemRootsPool()
		if opts.Roots == nil {
			return nil, SystemRootsError{systemRootsErr}
		}
	}

	err = c.isValid(leafCertificate, nil, &opts)
	if err != nil {
		return
	}

	if len(opts.DNSName) > 0 {
		err = c.VerifyHostname(opts.DNSName)
		if err != nil {
			return
		}
	}

	var candidateChains [][]*Certificate
	if opts.Roots.contains(c) {
		candidateChains = append(candidateChains, []*Certificate{c})
	} else {
		if candidateChains, err = c.buildChains(nil, []*Certificate{c}, nil, &opts); err != nil {
			return nil, err
		}
	}

	keyUsages := opts.KeyUsages
	if len(keyUsages) == 0 {
		keyUsages = []ExtKeyUsage{ExtKeyUsageServerAuth}
	}

	// 如果任何密钥使用都可以接受，那么我们就完成了。
	for _, usage := range keyUsages {
		if usage == ExtKeyUsageAny {
			return candidateChains, nil
		}
	}

	for _, candidate := range candidateChains {
		if checkChainForKeyUsage(candidate, keyUsages) {
			chains = append(chains, candidate)
		}
	}

	if len(chains) == 0 {
		return nil, CertificateInvalidError{c, IncompatibleUsage, ""}
	}

	return chains, nil
}

func appendToFreshChain(chain []*Certificate, cert *Certificate) []*Certificate {
	n := make([]*Certificate, len(chain)+1)
	copy(n, chain)
	n[len(chain)] = cert
	return n
}

// maxChainSignatureChecks是CheckSignatureFrom调用的最大数目
// 对构建链的调用将（通过传递）生成。大多数链条都是
// 少于15个证书的长度，因此为多个链和
// 由于不同中间产物具有相同主题而导致检查失败。
const maxChainSignatureChecks = 100

func (c *Certificate) buildChains(cache map[*Certificate][][]*Certificate, currentChain []*Certificate, sigChecks *int, opts *VerifyOptions) (chains [][]*Certificate, err error) {
	var (
		hintErr  error
		hintCert *Certificate
	)

	considerCandidate := func(certType int, candidate *Certificate) {
		for _, cert := range currentChain {
			if cert.Equal(candidate) {
				return
			}
		}

		if sigChecks == nil {
			sigChecks = new(int)
		}
		*sigChecks++
		if *sigChecks > maxChainSignatureChecks {
			err = errors.New("x509: signature check attempts limit reached while verifying certificate chain")
			return
		}

		if err := c.CheckSignatureFrom(candidate); err != nil {
			if hintErr == nil {
				hintErr = err
				hintCert = candidate
			}
			return
		}

		err = candidate.isValid(certType, currentChain, opts)
		if err != nil {
			return
		}

		switch certType {
		case rootCertificate:
			chains = append(chains, appendToFreshChain(currentChain, candidate))
		case intermediateCertificate:
			if cache == nil {
				cache = make(map[*Certificate][][]*Certificate)
			}
			childChains, ok := cache[candidate]
			if !ok {
				childChains, err = candidate.buildChains(cache, appendToFreshChain(currentChain, candidate), sigChecks, opts)
				cache[candidate] = childChains
			}
			chains = append(chains, childChains...)
		}
	}

	for _, root := range opts.Roots.findPotentialParents(c) {
		considerCandidate(rootCertificate, root)
	}
	for _, intermediate := range opts.Intermediates.findPotentialParents(c) {
		considerCandidate(intermediateCertificate, intermediate)
	}

	if len(chains) > 0 {
		err = nil
	}
	if len(chains) == 0 && err == nil {
		err = UnknownAuthorityError{c, hintErr, hintCert}
	}

	return
}

func validHostnamePattern(host string) bool { return validHostname(host, true) }
func validHostnameInput(host string) bool   { return validHostname(host, false) }

// validHostname报告主机是否为可匹配的有效主机名
// 根据RFC 6125 2.2进行匹配，并给予一定的宽大处理
// 遗产价值。
func validHostname(host string, isPattern bool) bool {
	if !isPattern {
		host = strings.TrimSuffix(host, ".")
	}
	if len(host) == 0 {
		return false
	}

	for i, part := range strings.Split(host, ".") {
		if part == "" {
			// 空标签。
			return false
		}
		if isPattern && i == 0 && part == "*" {
			// 只允许最左边的通配符，因为它们是唯一的通配符
			// 我们匹配，而匹配文字'*'字符可能永远都不会匹配
			// 预期的行为。
			continue
		}
		for j, c := range part {
			if 'a' <= c && c <= 'z' {
				continue
			}
			if '0' <= c && c <= '9' {
				continue
			}
			if 'A' <= c && c <= 'Z' {
				continue
			}
			if c == '-' && j != 0 {
				continue
			}
			if c == '_' {
				// 主机名中的无效字符，但通常为
				// 在WebPKI之外的部署中找到。
				continue
			}
			return false
		}
	}

	return true
}

func matchExactly(hostA, hostB string) bool {
	if hostA == "" || hostA == "." || hostB == "" || hostB == "." {
		return false
	}
	return toLowerCaseASCII(hostA) == toLowerCaseASCII(hostB)
}

func matchHostnames(pattern, host string) bool {
	pattern = toLowerCaseASCII(pattern)
	host = toLowerCaseASCII(strings.TrimSuffix(host, "."))

	if len(pattern) == 0 || len(host) == 0 {
		return false
	}

	patternParts := strings.Split(pattern, ".")
	hostParts := strings.Split(host, ".")

	if len(patternParts) != len(hostParts) {
		return false
	}

	for i, patternPart := range patternParts {
		if i == 0 && patternPart == "*" {
			continue
		}
		if patternPart != hostParts[i] {
			return false
		}
	}

	return true
}

// TOLOWERCEASCII返回in的小写版本。见RFC 6125 6.4.1。我们使用
// 一个明确的ASCII函数，以避免由于
// 在DNS标签上执行Unicode操作。
func toLowerCaseASCII(in string) string {
	// 如果字符串已经是小写的，则无需执行任何操作。
	isAlreadyLowerCase := true
	for _, c := range in {
		if c == utf8.RuneError {
			// 如果我们得到一个UTF-8错误，那么可能有
			// 无效序列中的大写ASCII字节。
			isAlreadyLowerCase = false
			break
		}
		if 'A' <= c && c <= 'Z' {
			isAlreadyLowerCase = false
			break
		}
	}

	if isAlreadyLowerCase {
		return in
	}

	out := []byte(in)
	for i, c := range out {
		if 'A' <= c && c <= 'Z' {
			out[i] += 'a' - 'A'
		}
	}
	return string(out)
}

// 如果c是指定主机的有效证书，则VerifyHostname返回nil。
// 否则，它将返回一个描述不匹配的错误。
// None
// 可以选择将IP地址括在方括号内并进行检查
// 针对IPAddresses字段。其他名称不区分大小写进行检查
// 反对DNSNames领域。如果名称是有效的主机名，则证书
// 字段可以有一个通配符作为最左边的标签。
// None
// 请注意，传统的通用名称字段将被忽略。
func (c *Certificate) VerifyHostname(h string) error {
	// IP地址可以用[]书写。
	candidateIP := h
	if len(h) >= 3 && h[0] == '[' && h[len(h)-1] == ']' {
		candidateIP = h[1 : len(h)-1]
	}
	if ip := net.ParseIP(candidateIP); ip != nil {
		// 我们只将IP地址与IP SAN进行匹配。
		// 见RFC 6125，附录B.2。
		for _, candidate := range c.IPAddresses {
			if ip.Equal(candidate) {
				return nil
			}
		}
		return HostnameError{c, candidateIP}
	}

	candidateName := toLowerCaseASCII(h) // 在循环内保存分配。
	validCandidateName := validHostnameInput(candidateName)

	for _, match := range c.DNSNames {
		// 理想情况下，我们只能根据RFC6125匹配有效的主机名
		// 浏览器（或多或少）确实如此，但实际上Go的使用范围更广
		// 上下文数组，甚至不能假定DNS解析。相反
		// 始终允许完全匹配，并且仅应用通配符和尾随符
		// 对有效主机名进行点处理。
		if validCandidateName && validHostnamePattern(match) {
			if matchHostnames(match, candidateName) {
				return nil
			}
		} else {
			if matchExactly(match, candidateName) {
				return nil
			}
		}
	}

	return HostnameError{c, h}
}

func checkChainForKeyUsage(chain []*Certificate, keyUsages []ExtKeyUsage) bool {
	usages := make([]ExtKeyUsage, len(keyUsages))
	copy(usages, keyUsages)

	if len(chain) == 0 {
		return false
	}

	usagesRemaining := len(usages)

	// 我们沿着列表走下去，划掉所有不受支持的用法
	// 凭每一张证书。如果我们划掉所有的用法，那么链条
	// 这是不能接受的。

NextCert:
	for i := len(chain) - 1; i >= 0; i-- {
		cert := chain[i]
		if len(cert.ExtKeyUsage) == 0 && len(cert.UnknownExtKeyUsage) == 0 {
			// 证书未指定任何扩展密钥用法。
			continue
		}

		for _, usage := range cert.ExtKeyUsage {
			if usage == ExtKeyUsageAny {
				// 该证书明确适用于任何用途。
				continue NextCert
			}
		}

		const invalidUsage ExtKeyUsage = -1

	NextRequestedUsage:
		for i, requestedUsage := range usages {
			if requestedUsage == invalidUsage {
				continue
			}

			for _, usage := range cert.ExtKeyUsage {
				if requestedUsage == usage {
					continue NextRequestedUsage
				} else if requestedUsage == ExtKeyUsageServerAuth &&
					(usage == ExtKeyUsageNetscapeServerGatedCrypto ||
						usage == ExtKeyUsageMicrosoftServerGatedCrypto) {
					// 为了支持科摩多
					// 证书链，我们必须
					// 接受Netscape或Microsoft SGC
					// 用法等同于ServerAuth。
					continue NextRequestedUsage
				}
			}

			usages[i] = invalidUsage
			usagesRemaining--
			if usagesRemaining == 0 {
				return false
			}
		}
	}

	return true
}
